﻿#include "ssWsppNetwork.h"
#include "../ssServerErrorDefine.h"
#include "message/ssMsgIdDef.h"
#include "message/ssNetMsgHead.h"
#include "log/ssLogThread.h"

namespace StarSeeker
{

ssWsppNetwork::ssWsppNetwork()
{
}

ssWsppNetwork::~ssWsppNetwork()
{
}

bool ssWsppNetwork::StartNetWork(const char* ip, const u16 port, bool isV6)
{
	try {
		// Set logging settings
		m_echoServer.clear_access_channels(websocketpp::log::alevel::all);
		m_echoServer.clear_error_channels(websocketpp::log::alevel::all);

		// Initialize Asio
		m_echoServer.init_asio();

		m_ioService = &m_echoServer.get_io_service();

		// Register our message handler
		m_echoServer.set_message_handler(bind(&ssWsppNetwork::OnMessage, this, &m_echoServer, ::_1, ::_2));
		m_echoServer.set_socket_init_handler(bind(&ssWsppNetwork::OnSocketInit, this, ::_1, ::_2));
		m_echoServer.set_fail_handler(bind(&ssWsppNetwork::OnFail, this, ::_1));
		m_echoServer.set_close_handler(bind(&ssWsppNetwork::OnClose, this, ::_1));
		m_echoServer.set_open_handler(bind(&ssWsppNetwork::OnOpen, this, ::_1));
		//m_echoServer.set_interrupt_handler(bind(&ssWsppNetwork::OnInterrupt, this, ::_1));
		//m_echoServer.set_http_handler(bind(&ssWsppNetwork::OnHttp, this, &m_echoServer, ::_1));

		// Listen on port 9002
		if (isV6)
			m_addr.address(asio::ip::address_v6::from_string(ip));
		else
			m_addr.address(asio::ip::address_v4::from_string(ip));
		m_addr.port(port);
		m_echoServer.listen(m_addr);

		// Start the server accept loop
		m_echoServer.start_accept();

		SS_LOG->PrintEx("start listen %s:%d", ip,port);
		for (u16 i = 0; i < m_threadCount; i++)
		{
			m_threads.push_back(websocketpp::lib::make_shared<websocketpp::lib::thread>(&server::run, &m_echoServer));
		}

		return true;
	}
	catch (websocketpp::exception const & e) {
		//std::cout << e.what() << std::endl;
		SS_LOG->ErrorEx("ssWsppNetwork::StartNetWork %s:%d", e.what(), e.code());
		return false;
	}
	catch (...) {
		return false;
	}
}

void ssWsppNetwork::StopNetWork()
{
	try{
		m_echoServer.stop_listening();
		m_echoServer.stop();
		for (u32 i = 0; i < m_threads.size(); ++i)
		{
			m_threads[i]->join();
		}
	}
	catch (websocketpp::exception const & e) {
		//std::cout << "exception: " << e.what() << std::endl;
		SS_LOG->Error(e.what());
	}
}

void ssWsppNetwork::DoCloseSocket(u32 sessionId)
{
	m_ioService->post(bind(&ssWsppNetwork::HandleClose, this, sessionId));
}

void ssWsppNetwork::DoSendData(u32 sessionId, const char* buf, u32 len)
{
	m_ioService->post(bind(&ssWsppNetwork::HandleSend, this, sessionId, buf, len));
}

void ssWsppNetwork::DoSendDataMulti(std::vector<u32>* sessionId, const char* buf, u32 len)
{
	m_ioService->post(bind(&ssWsppNetwork::HandleSendMulti, this, sessionId, buf, len));
}

void ssWsppNetwork::HandleClose(u32 sessionId)
{
	//找到id
	std::map<u32, ssWsppSession*>::iterator itr = m_sessionId.find(sessionId);
	if (itr != m_sessionId.end())
	{
		try
		{
			m_echoServer.close(itr->second->m_hdl, websocketpp::close::status::normal, "close by server");
		}
		catch (const websocketpp::exception& e)
		{
			SS_LOG->ErrorEx("ssWsppNetwork::HandleClose %s", e.what());
		}
		catch (const websocketpp::lib::error_code& e)
		{
			SS_LOG->ErrorEx("ssWsppNetwork::HandleClose %s", e.message().c_str());
		}
		catch (...)
		{
			SS_LOG->Error("ssWsppNetwork::HandleClose error");
		}
	}
}

void ssWsppNetwork::HandleSend(u32 sessionId, const char* buf, u32 len)
{
	if (buf && len)
	{
		//找到id
		std::map<u32, ssWsppSession*>::iterator itr = m_sessionId.find(sessionId);
		if (itr != m_sessionId.end())
		{
			if (itr->second->IsConnected())
			{
				try
				{
					m_echoServer.send(itr->second->m_hdl, buf, len, websocketpp::frame::opcode::binary);
				}
				catch (const websocketpp::exception& e)
				{
					SS_LOG->ErrorEx("ssWsppNetwork::HandleSend %s", e.what());
				}
				catch (const websocketpp::lib::error_code& e)
				{
					SS_LOG->ErrorEx("ssWsppNetwork::HandleSend %s", e.message().c_str());
				}
				catch (...)
				{
					SS_LOG->Error("ssWsppNetwork::HandleSend error");
				}
			}
		}
	}
	SS_SAFE_DEL_ARRAY(buf)
}

void ssWsppNetwork::HandleSendMulti(std::vector<u32>* sessionId, const char* buf, u32 len)
{
	if (sessionId && buf && len)
	{
		for (u32 i = 0; i < sessionId->size(); ++i)
		{
			//找到id
			std::map<u32, ssWsppSession*>::iterator itr = m_sessionId.find((*sessionId)[i]);
			if (itr != m_sessionId.end())
			{
				if (itr->second->IsConnected())
				{
					try
					{
						m_echoServer.send(itr->second->m_hdl, buf, len, websocketpp::frame::opcode::binary);
					}
					catch (const websocketpp::exception& e)
					{
						SS_LOG->ErrorEx("ssWsppNetwork::HandleSend %s", e.what());
					}
					catch (const websocketpp::lib::error_code& e)
					{
						SS_LOG->ErrorEx("ssWsppNetwork::HandleSend %s", e.message().c_str());
					}
					catch (...)
					{
						SS_LOG->Error("ssWsppNetwork::HandleSend error");
					}
				}
			}
		}
	}
	SS_SAFE_DEL_ARRAY(buf)
	SS_SAFE_DELETE(sessionId)
}

void ssWsppNetwork::DeleteSession(websocketpp::connection_hdl hdl)
{
	//找到id
	std::map<void*, ssWsppSession*>::iterator itr = m_sessionHdl.find(hdl.lock().get());
	if (itr != m_sessionHdl.end())
	{
		//抛给逻辑
		//m_pNetworkMgr->PostMsg(SS_MSG_ID_DISCONNECT, 0, 0, itr->second);

		//删除连接
		ssWsppSession* session = itr->second;
		OnSessionClose(session->m_sessionID);
		m_sessionId.erase(session->m_sessionID);
		m_sessionHdl.erase(itr);
		//!!需要对象池
		delete session;
	}
}

void ssWsppNetwork::OnMessage(server* s, websocketpp::connection_hdl hdl, message_ptr msg)
{
	if (msg->get_opcode() != websocketpp::frame::opcode::binary)
	{
		s->close(hdl, websocketpp::close::status::unsupported_data, "not websocketpp::frame::opcode::binary");
		return;
	}
	
	if (!msg->get_payload().empty())
	{
		u32 len = msg->get_payload().size();
		if (len > 1024*20)
		{
			s->close(hdl, websocketpp::close::status::message_too_big, "data too long");
			return;
		}
		//找到id
		std::map<void*, ssWsppSession*>::iterator itr = m_sessionHdl.find(hdl.lock().get());
		if (itr == m_sessionHdl.end())
		{
			s->close(hdl, websocketpp::close::status::protocol_error, "session id error");
			return;
		}
		//判断包头
		ssNetMsgHead* head = (ssNetMsgHead*)msg->get_payload().data();
		if (head->m_dwLen != len)
		{
			return;
		}
		bool32 ret = itr->second->OnReceive(head);
		if (ret != SS_SUCCESS)
		{
			std::string err = "illegal msg";
			switch (ret)
			{
			case SS_CONNECT_FAST:
				err = "msg too fast";
				break;
			case SS_DISCONNECT:
				err = "socket is disconnect";
				break;
			}
			s->close(hdl, websocketpp::close::status::invalid_payload, err);
			return;
		}
		//!!需要对象池
		char *buf = new char[len];
		memcpy(buf, msg->get_payload().data(), len);
		OnSessionMessage(itr->second->m_sessionID, itr->second->GetIp(), head->m_dwMsgID, buf, (ssNetMsgHead*)buf);
	}
}

void ssWsppNetwork::OnSocketInit(websocketpp::connection_hdl hdl, asio::ip::tcp::socket & s)
{
	asio::ip::tcp::no_delay option(true);
	s.set_option(option);
	//分配一个连接对象
	//!!需要对象池
	ssWsppSession* session = new ssWsppSession();
	u32 id = m_idAlloter.GetID();
	session->Init(id, hdl, &s, this);
	if (m_timeCheck)
		session->SetTimeCheck(true);
	m_sessionId.insert(std::pair<u32, ssWsppSession*>(id, session));
	m_sessionHdl.insert(std::pair<void*, ssWsppSession*>(hdl.lock().get(), session));
}

void ssWsppNetwork::OnFail(websocketpp::connection_hdl hdl)
{
	DeleteSession(hdl);
}

void ssWsppNetwork::OnClose(websocketpp::connection_hdl hdl)
{
	DeleteSession(hdl);
}

void ssWsppNetwork::OnOpen(websocketpp::connection_hdl hdl)
{
	//找到id
	std::map<void*, ssWsppSession*>::iterator itr = m_sessionHdl.find(hdl.lock().get());
	if (itr != m_sessionHdl.end())
	{
		if (m_sessionId.size() > m_sessionCount)
		{
			HandleClose(itr->second->m_sessionID);
			return;
		}
		itr->second->OnOpen();
		//抛给逻辑
		//m_pNetworkMgr->PostMsg(SS_MSG_ID_NEW_CONNECT, 0, id, (ulint)session);
		OnNewSession(itr->second->m_sessionID);
	}
}

}
